#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <getopt.h>
#include "base64_utils.h"
#include "mailUtil.h"

#define MAX_SIZE 4095

char buf[MAX_SIZE+1];
#define swap16(x) ((((x)&0xFF) << 8) | (((x) >> 8) & 0xFF)) //为16位数据交换大小端
// receiver: mail address of the recipient
// subject: mail subject
// msg: content of mail body or path to the file containing mail body
// att_path: path to the attachment


char *add_content(char *dst, const char *src){
    strcat(dst,src);
    strcat(dst,"\n");
}

char *add_header(char *dst, const char *src){
    strcat(dst,src);
}
char *end_data(char *dst){
    strcat(dst,"\r\n.\r\n");
}

/*
 * 接受内容并且打印出来
 * */
void receivePrint(int s_fd,char *send_buf){
    int r_size;
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive to message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);
}

void sendData(){
}

void send_mail(const char* receiver, const char* subject, const char* msg, const char* att_path)
{
    printf("\ntest 5: %s\n",msg);
    char *send_buf = malloc(8388608*sizeof(char));
    const char* host_name = "smtp.qq.com"; // TODO: Specify the mail server domain name
    const unsigned short port = 25; // SMTP server port
    const char* user = ""; // TODO: Specify the user
    const char* pass = ""; // TODO: Specify the password
    const char* from = "zesenxie@foxmail.com"; // TODO: Specify the mail address of the sender
    const char* to = "1271783358@qq.com";
    char dest_ip[16]; // Mail server IP address
    int s_fd; // socket file descriptor
    struct hostent *host;
    struct in_addr **addr_list;
    int i = 0;
    int r_size;
    char *blank = " ";
    // Get IP from domain name
    if ((host = gethostbyname(host_name)) == NULL)
    {
        herror("gethostbyname");
        exit(EXIT_FAILURE);
    }

    addr_list = (struct in_addr **) host->h_addr_list;
    while (addr_list[i] != NULL)
        ++i;
    strcpy(dest_ip, inet_ntoa(*addr_list[i-1]));

    // TODO: Create a socket, return the file descriptor to s_fd, and establish a TCP connection to the mail server
    s_fd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in servaddr;
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = swap16(port);
    bzero(servaddr.sin_zero,8);
    struct in_addr ip_des;
    ip_des.s_addr = inet_addr(dest_ip);
    servaddr.sin_addr = ip_des;

    if (connect(s_fd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr_in))==-1){
        perror("error in connect");
        exit(EXIT_FAILURE);
    }
    // Print welcome message
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive welcome message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
   memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);
    printf("-------------------------\n");
    // Send EHLO command and print server response
    const char* EHLO = strcat(strcat(strcpy(send_buf,"ehlo "),host_name),"\r\n"); // TODO: Enter EHLO command here
    int count = send(s_fd, EHLO, strlen(EHLO), 0);
    // TODO: Print server response to EHLO command
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive EHLO message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);
    // TODO: Authentication. Server response should be printed out.
    char *loginMessage = strcat(strcpy(send_buf,"auth login"),"\r\n");
    send(s_fd, loginMessage, strlen(loginMessage), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive from message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);


    char *loginUser = strcat(strcpy(send_buf,"MTI3MTc4MzM1OEBxcS5jb20="),"\r\n");
    send(s_fd, loginUser, strlen(loginUser), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive from message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);

    char *loginPwd = strcat(strcpy(send_buf,"dWtsc3N3aXBxZmFhZ2ppag=="),"\r\n");
    send(s_fd, loginPwd, strlen(loginPwd), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive from message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);
    // TODO: Send MAIL FROM command and print server response
    char *fromMessage = strcat(strcat(strcpy(send_buf,"mail from:<"),from),">\r\n");
    send(s_fd, fromMessage, strlen(fromMessage), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive from message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);

    // TODO: Send RCPT TO command and print server response
    char *toMessage = strcat(strcat(strcpy(send_buf,"rcpt to:<"),receiver),">\r\n");
    send(s_fd, toMessage, strlen(toMessage), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive to message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);

    // TODO: Send DATA command and print server response
    char *dataCommand = "data\r\n";
    send(s_fd, dataCommand, strlen(dataCommand), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive to message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);

    // TODO: Send message data
    char *boundary = "--qwertyuiopasdfghjklzxcvbnm";
    strcpy(send_buf,"Subject:");
    add_content(send_buf,subject);
    add_header(send_buf,"from: ");
    add_content(send_buf,from);
    add_header(send_buf,"to:");
    add_content(send_buf,to);
    add_content(send_buf,"MIME-Version: 1.0");
    printf("\n test 3: %s \n",send_buf);
    // add_content(send_buf,"Content-Description: 1.0");
    add_content(send_buf,"Content-Type: multipart/mixed; boundary=qwertyuiopasdfghjklzxcvbnm");
//    添加text类型内容
    add_content(send_buf,boundary);
    add_header(send_buf,"Content-Type: ");
    add_content(send_buf,"text/plain; charset=gb18030");
    add_content(send_buf,"Content-Transfer-Encoding: base64");
    char *sendText = getFileAsChar(msg);
    printf("test 2:\n %s",sendText);
    if (sendText == NULL){
        add_content(send_buf,encode_str(msg));
    }else{
        char *s = encode_str(sendText);
        printf("\n test 4:%s \n",s);
        add_content(send_buf,s);
    }
//    在添加附件前先发送出去试试？避免太大爆了缓存
    printf("\n tt:%s \n",send_buf);
    send(s_fd, send_buf, strlen(send_buf), 0);
    // memset函数使用错误造成的麻烦
    // memset(send_buf,MAX_SIZE,0);
    memset(send_buf, 0, MAX_SIZE);
//    添加附件
    if (att_path !=NULL){
        FILE *f = fopen(att_path,"r");
        if (f!=NULL)
        {
            FILE * newFile;
            char *newFileName = "guafile";
            newFile = fopen(newFileName,"w");
            long count;
            count=encode_file(f,newFile);


            strcpy(send_buf,boundary);
            strcat(send_buf,"\n");
            add_header(send_buf,"Content-Type: ");
            add_header(send_buf,"application/octet-stream; charset=ISO-8859-1; ");
            add_header(send_buf,"name=");
            add_content(send_buf,att_path);
            add_content(send_buf,"Content-Disposition: attachment;");
            add_header(send_buf,"Content-Transfer-Encoding: ");
            add_content(send_buf,"base64");

            send(s_fd, send_buf, strlen(send_buf), 0);
            printf("\n tt2:%s \n",send_buf);
            memset(send_buf, 0, MAX_SIZE);


// final method:read file as single char and send them out
            FILE *guaFile = fopen(newFileName,"r");
            int nCount;
            // 现在使用的是正片发送的方案，后期可以优化为分片发送
            while( (nCount = fread(send_buf, 1, count, guaFile)) > 0 ){
                send(s_fd, send_buf, nCount, 0);
            }
        }
      }

    // TODO: Message ends with a single period
    end_data(send_buf);
    send(s_fd, send_buf, strlen(send_buf), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive to message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);

 

    // TODO: Send QUIT command and print server response
    char *quitCommand = "quit\r\n";
    send(s_fd, quitCommand, strlen(quitCommand), 0);
    if ((r_size = recv(s_fd, buf, MAX_SIZE, 0)) == -1)
    {
        perror("error in receive to message\n");
        exit(EXIT_FAILURE);
    }
    buf[r_size] = '\0'; // Do not forget the null terminator
    printf("%s", buf);
    printf("-------------------------\n");
    memset(buf,0,MAX_SIZE);
    memset(send_buf, 0, MAX_SIZE);
    close(s_fd);
}



int main(int argc, char* argv[])
{
    for (int i = 0; i < argc; ++i) {
        fprintf(stdout, "%s\n",argv[i]);
    }
    int opt;
    char* s_arg = NULL;
    char* m_arg = NULL;
    char* a_arg = NULL;
    char* recipient = NULL;
    const char* optstring = ":s:m:a:";
    fprintf(stdout, "---------------------------------\n");
    while ((opt = getopt(argc, argv, optstring)) != -1)
    {
        fprintf(stdout, "%c\n",opt);
        fprintf(stdout, "-----\n");
        switch (opt)
        {
            case 's':
                s_arg = optarg;
                break;
            case 'm':
                m_arg = optarg;
                break;
            case 'a':
                a_arg = optarg;
                break;
            case ':':
                fprintf(stderr, "Option %c needs an argument.\n", optopt);
                exit(EXIT_FAILURE);
            case '?':
                fprintf(stderr, "Unknown option: %c.\n", optopt);
                exit(EXIT_FAILURE);
            default:
                fprintf(stderr, "Unknown error.\n");
                exit(EXIT_FAILURE);
        }
    }

    fprintf(stdout, "%d\n",optind);
    fprintf(stdout, "%d\n",argc);

    if (optind == argc)
    {
        fprintf(stderr, "Recipient not specified.\n");
        exit(EXIT_FAILURE);
    }
    else if (optind < argc - 1)
    {
        fprintf(stderr, "Too many arguments.\n");
        exit(EXIT_FAILURE);
    }
    else
    {
        recipient = argv[optind];
        send_mail(recipient, s_arg, m_arg, a_arg);
        exit(0);
    }
}
